package lz.controls.containers
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	import lz.controls.ScrollBar;
	import lz.controls.ScrollBarDirection;
	import lz.controls.ScrollPolicy;
	import lz.controls.core.InvalidationType;
	import lz.controls.core.UIComponent;
	import lz.controls.events.ScrollEvent;

	/**
	 * BaseScrollPane 类处理基本的滚动窗格功能，包括事件、样式、绘制遮罩和背景、滚动条的布局以及滚动位置的处理。
	 * 默认情况下，ScrollPane 和 SelectableList 类对 BaseScrollPane 类进行扩展，使其适用于所有基于列表的组件。 
 	 * 这意味着，使用水平或垂直滚动的任何组件不需要实现任何滚动、遮罩或布局逻辑（特定于组件的行为除外）。
	 */
	public class BaseScrollPane extends UIComponent
	{
		/**
		 * 竖向滚动条
		 */
		protected var _verticalScrollBar:ScrollBar;
		/**
		 * 横向滚动条
		 */
		protected var _horizontalScrollBar:ScrollBar;
		/**
         * 内容滚动区域
		 */
		protected var contentScrollRect:Rectangle;
		/**
         * @private (protected)
		 */
		protected var disabledOverlay:Shape;
		/**
         *背景
		 */
		protected var background:DisplayObject;
		/**
		 * 容器的宽
		 */
		protected var contentWidth:Number=0;
		/**
		 * 容器的高
		 */
		protected var contentHeight:Number=0;
		/**
         * 该值指示水平滚动条的状态
		 */
		protected var _horizontalScrollPolicy:String;
		/**
         * 该值指示垂直滚动条的状态
		 */
		protected var _verticalScrollPolicy:String;
		/**
		 * 容器的底
		 */
		protected var contentPadding:Number=0;
		/**
		 * 有效的宽
		 */
		protected var availableWidth:Number;
		/**
		 * 有效的高
		 */
		protected var availableHeight:Number;
		/**
         * @private (protected)
		 */
		protected var vOffset:Number = 0;
		/**
         * @private (protected)
		 */
		protected var vScrollBar:Boolean;
		/**
         * @private (protected)
		 */
		protected var hScrollBar:Boolean;
		/**
         * @private (protected)
		 */
		protected var _maxHorizontalScrollPosition:Number = 0;		
		/**
         * @private (protected)
		 */
		protected var _horizontalPageScrollSize:Number = 0;	
		/**
         * @private (protected)
		 */
		protected var _verticalPageScrollSize:Number = 0;
		/**
         * @private (protected)
		 */
		protected var defaultLineScrollSize:Number = 4;
		
		/**
         * @private (protected)
         *
         * If <code>false</code>, uses <code>contentWidth</code> to determine hscroll, otherwise uses fixed <code>_maxHorizontalScroll</code> value.
		 */
		protected var useFixedHorizontalScrolling:Boolean = false; // if false, uses contentWidth to determine hscroll, otherwise uses fixed _maxHorizontalScroll value
		
		/**
         * @private (protected)
		 */
		protected var _useBitmpScrolling:Boolean = false;
		
		/**
		 * 默认样式 
		 */
		private static var defaultStyles:Object = {	 
											repeatDelay:500,repeatInterval:35,
											skin:"ScrollPane_upSkin",
											contentPadding:0,
											disabledAlpha:0.5
											};
		/**
		 * 检索当前组件的默认样式映射 
		 */
		public static function getStyleDefinition():Object 
		{ 
			return mergeStyles(defaultStyles, ScrollBar.getStyleDefinition());
		}

		
		/**
		 * 滚动条样式 
		 */
		protected static const SCROLL_BAR_STYLES:Object = {
											upArrowDisabledSkin: "upArrowDisabledSkin",
											upArrowDownSkin:"upArrowDownSkin",
											upArrowOverSkin:"upArrowOverSkin",
											upArrowUpSkin:"upArrowUpSkin",
											downArrowDisabledSkin:"downArrowDisabledSkin",
											downArrowDownSkin:"downArrowDownSkin",
											downArrowOverSkin:"downArrowOverSkin",
											downArrowUpSkin:"downArrowUpSkin",
											thumbDisabledSkin:"thumbDisabledSkin",
											thumbDownSkin:"thumbDownSkin",
											thumbOverSkin:"thumbOverSkin",
											thumbUpSkin:"thumbUpSkin",
											thumbIcon:"thumbIcon",
											trackDisabledSkin:"trackDisabledSkin",
											trackDownSkin:"trackDownSkin",
											trackOverSkin:"trackOverSkin",
											trackUpSkin:"trackUpSkin",
											repeatDelay:"repeatDelay",
											repeatInterval:"repeatInterval"
											};


		/**
         * Creates a new BaseScrollPane component instance.
		 */
		public function BaseScrollPane() 
		{
			super();
        }
		/**
		 * 滚动条是否可用
		 */
		override public function set enabled(value:Boolean):void 
		{
			if (enabled == value)
			{ 
				return;
			}
			_verticalScrollBar.enabled = value;
			_horizontalScrollBar.enabled = value;
			super.enabled = value;
		}
		/**
         *获取或设置一个值，该值指示水平滚动条的状态。 
		 * ScrollPolicy.ON 值指示水平滚动条始终打开；
		 * ScrollPolicy.OFF 值指示水平滚动条始终关闭；
		 * ScrollPolicy.AUTO 值指示其状态自动更改。 
		 * 该属性与其他滚动属性一起用来设置滚动条的 setScrollProperties() 方法。
		 * 默认值为 ScrollPolicy.AUTO。
		 */
		public function get horizontalScrollPolicy():String
		{
			return _horizontalScrollPolicy;
		}
		public function set horizontalScrollPolicy(value:String):void
		{
			_horizontalScrollPolicy = value;
			invalidate(InvalidationType.SIZE);
		}
		/**
         *获取或设置一个值，该值指示垂直滚动条的状态。
		 * ScrollPolicy.ON 值指示垂直滚动条始终打开；
		 * ScrollPolicy.OFF 值指示垂直滚动条始终关闭；
		 * ScrollPolicy.AUTO 值指示其状态自动更改。 
		 * 该属性与其他滚动属性一起用来设置滚动条的 setScrollProperties() 方法。
		 * 默认值为 ScrollPolicy.AUTO。
		 */
		public function get verticalScrollPolicy():String 
		{
			return _verticalScrollPolicy;
		}		
		public function set verticalScrollPolicy(value:String):void 
		{
			_verticalScrollPolicy = value;
			invalidate(InvalidationType.SIZE);
		}
		/**
		 * 获取或设置一个值，该值描述当单击滚动箭头时要在水平方向上滚动的内容量。 
		 * 该值以像素为单位。
		 * 默认值为 4。
		 */
		public function get horizontalLineScrollSize():Number
		{
			return _horizontalScrollBar.lineScrollSize;
		}
		public function set horizontalLineScrollSize(value:Number):void 
		{
			_horizontalScrollBar.lineScrollSize = value;
		}
		/**
		 *获取或设置一个值，该值描述当单击滚动箭头时要在垂直方向上滚动多少像素。
		 * 默认值为 4。
		 */
		public function get verticalLineScrollSize():Number 
		{
			return _verticalScrollBar.lineScrollSize;
		}
		public function set verticalLineScrollSize(value:Number):void 
		{
			_verticalScrollBar.lineScrollSize = value;
		}
		/**
		 *获取或设置一个值，该值描述滚动窗格中水平滚动条的水平位置（以像素为单位）。
		 * 默认值为 0。
		 */
		public function get horizontalScrollPosition():Number
		{
			return _horizontalScrollBar.scrollPosition;
		}
		public function set horizontalScrollPosition(value:Number):void 
		{
			// We must force a redraw to ensure that the size is up to date.
			drawNow();
			
			_horizontalScrollBar.scrollPosition = value;
			setHorizontalScrollPosition(_horizontalScrollBar.scrollPosition,false);
		}
		/**
		 * 获取或设置一个值，该值描述滚动窗格中垂直滚动条的垂直位置（以像素为单位）。
		 * 默认值为 0。
		 */
		public function get verticalScrollPosition():Number 
		{
			return _verticalScrollBar.scrollPosition;
		}
		public function set verticalScrollPosition(value:Number):void 
		{
			// We must force a redraw to ensure that the size is up to date.
			drawNow();
			
			_verticalScrollBar.scrollPosition = value;
			setVerticalScrollPosition(_verticalScrollBar.scrollPosition,false);
		}
		/**
		 * 获取当前内容的最大水平滚动位置（以像素为单位）。
		 */
		public function get maxHorizontalScrollPosition():Number
		{
			drawNow();
			return Math.max(0,contentWidth-availableWidth);
		}
		/**
		 * 获取当前内容的最大垂直滚动位置（以像素为单位）。
		 */
		public function get maxVerticalScrollPosition():Number
		{
			drawNow();
			return Math.max(0,contentHeight-availableHeight);
		}
		/**
		 *设置为 true 时，滚动内容的 cacheAsBitmap 属性设置为 true；设置为 false 时，该值会关闭。
		 * 注意：将此属性设置为 true 可提高滚动性能。
		 * 默认值为 false。
		 */
		public function get useBitmapScrolling():Boolean
		{
			return _useBitmpScrolling;
		}
		public function set useBitmapScrolling(value:Boolean):void 
		{
			_useBitmpScrolling = value;
			invalidate(InvalidationType.STATE);
		}
		/**
		 *获取或设置按滚动条轨道时水平滚动条上滚动滑块要移动的像素数。 
		 * 当该值为 0 时，该属性检索组件的可用宽度。
		 * 默认值为 0。
         */
		public function get horizontalPageScrollSize():Number 
		{
			if (isNaN(availableWidth)) { drawNow(); }
			return (_horizontalPageScrollSize == 0 && !isNaN(availableWidth)) ? availableWidth : _horizontalPageScrollSize;
		}
		public function set horizontalPageScrollSize(value:Number):void 
		{
			_horizontalPageScrollSize = value;
			invalidate(InvalidationType.SIZE);	
		}
		/**
         * 获取或设置按滚动条轨道时垂直滚动条上滚动滑块要移动的像素数。 
		 * 当该值为 0 时，该属性检索组件的可用高度。
		 * 默认值为 0。
         */
		public function get verticalPageScrollSize():Number 
		{
			if (isNaN(availableHeight)) { drawNow(); }
			return (_verticalPageScrollSize == 0 && !isNaN(availableHeight)) ? availableHeight : _verticalPageScrollSize;
		}
		public function set verticalPageScrollSize(value:Number):void 
		{
			_verticalPageScrollSize = value;
			invalidate(InvalidationType.SIZE);	
		}
		
		/**
		 * 获取设置横向滚动条
		 */
		public function get horizontalScrollBar():ScrollBar
		{
			return _horizontalScrollBar;
		}
		public function set horizontalScrollBar(value :ScrollBar):void
		{
			if(value == null)
			{
				return;
			}
			if(_horizontalScrollBar && _horizontalScrollBar.parent)
			{
				_horizontalScrollBar.parent.removeChild(_horizontalScrollBar);
			}
			_horizontalScrollBar = value;
			_horizontalScrollBar.direction = ScrollBarDirection.HORIZONTAL;
			_horizontalScrollBar.addEventListener(ScrollEvent.SCROLL,handleScroll,false,0,true);
			_horizontalScrollBar.visible = false;
			_horizontalScrollBar.lineScrollSize = defaultLineScrollSize;
			addChild(_horizontalScrollBar);
			copyStylesToChild(_horizontalScrollBar,SCROLL_BAR_STYLES);
		}
		/**
		 * 获取设置竖向滚动条
		 */
		public function get verticalScrollBar():ScrollBar 
		{
			return _verticalScrollBar;
		}		
		public function set verticalScrollBar(value :ScrollBar):void
		{
			if(value == null)
			{
				return;
			}
			if(_verticalScrollBar && _verticalScrollBar.parent)
			{
				_verticalScrollBar.parent.removeChild(_verticalScrollBar);
			}
			_verticalScrollBar = value;
			_verticalScrollBar.addEventListener(ScrollEvent.SCROLL,handleScroll,false,0,true);
			_verticalScrollBar.visible = false;
			_verticalScrollBar.lineScrollSize = defaultLineScrollSize;
			addChild(_verticalScrollBar);
			copyStylesToChild(_verticalScrollBar,SCROLL_BAR_STYLES);
		}
		/**
         * 配置UI
		 */
		override protected function configUI():void 
		{
			super.configUI();

			//contentScrollRect is not actually used by BaseScrollPane, only by subclasses.
			contentScrollRect = new Rectangle(0,0,85,85);

			// set up vertical scroll bar:
			verticalScrollBar = new ScrollBar();

			// set up horizontal scroll bar:
			horizontalScrollBar = new ScrollBar();
			
			// Create the disabled overlay
			disabledOverlay = new Shape();
			var g:Graphics = disabledOverlay.graphics;
			g.beginFill(0xFFFFFF);
			g.drawRect(0,0,width,height);
			g.endFill();
			
			addEventListener(MouseEvent.MOUSE_WHEEL,handleWheel,false,0,true);
		}

		/**设置容器大小（目标）
         * @private (protected)
		 */
		protected function setContentSize(width:Number,height:Number):void 
		{
			if ((contentWidth == width || useFixedHorizontalScrolling) && contentHeight == height) { return; }
			
			contentWidth = width;
			contentHeight = height;
			invalidate(InvalidationType.SIZE);
		}

        /**
		 * 处理滚动事件 
         * @private (protected)
		 */
		protected function handleScroll(event:ScrollEvent):void 
		{
			if (event.target == _verticalScrollBar) 
			{
				setVerticalScrollPosition(event.position);
			} else
			{
				setHorizontalScrollPosition(event.position);
			}
		}

        /**
		 * 处理鼠标滑动
         * @private (protected)
		 */
		protected function handleWheel(event:MouseEvent):void 
		{
			if (!enabled || !_verticalScrollBar.visible || contentHeight <= availableHeight)
			{
				return;
			}
			_verticalScrollBar.scrollPosition -= event.delta * verticalLineScrollSize;
			setVerticalScrollPosition(_verticalScrollBar.scrollPosition);
			
			dispatchEvent(new ScrollEvent(ScrollBarDirection.VERTICAL, event.delta, horizontalScrollPosition));
		}

		// These are meant to be overriden by subclasses:
		/**
         * @private (protected)
		 */
		protected function setHorizontalScrollPosition(scroll:Number,fireEvent:Boolean=false):void {}
		/**
         * @private (protected)
		 */
		protected function setVerticalScrollPosition(scroll:Number,fireEvent:Boolean=false):void {}
		/**
		 * 绘制滚动条
         * @private (protected)
		 */
		override protected function draw():void
		{
			if (isInvalid(InvalidationType.STYLES)) 
			{
				setStyles();
				drawBackground();
				// drawLayout is expensive, so only do it if padding has changed:
				if (contentPadding != getStyleValue("contentPadding")) 
				{
					invalidate(InvalidationType.SIZE,false);
				}
			}
			if (isInvalid(InvalidationType.SIZE, InvalidationType.STATE)) 
			{
				drawLayout();
			}
			// Call drawNow() on nested components to get around problems with nested render events:
			updateChildren();
			super.draw();
		}

		/**
		 * 设置样式
         * @private (protected)
		 */
		protected function setStyles():void
		{
			copyStylesToChild(_verticalScrollBar,SCROLL_BAR_STYLES);
			copyStylesToChild(_horizontalScrollBar,SCROLL_BAR_STYLES);
		}

        /**
		 * 画背景
         * @private (protected)
		 */
		protected function drawBackground():void 
		{
			var bg:DisplayObject = background;
			
			background = getDisplayObjectInstance(getStyleValue("skin"));
			if(background == null)
			{
				background = new Sprite();
			}
			background.width = width;
			background.height = height;
			addChildAt(background,0);
			
			if (bg != null && bg != background) { removeChild(bg); }
		}

        /**
		 * 布局
         * @private (protected)
		 */
		protected function drawLayout():void 
		{
			calculateAvailableSize();
			calculateContentWidth();
			
			background.width = width;
			background.height = height;

			if (vScrollBar)
			{
				_verticalScrollBar.visible = true;
				_verticalScrollBar.x = width - ScrollBar.WIDTH - contentPadding;
				_verticalScrollBar.y = contentPadding;
				_verticalScrollBar.height = availableHeight;
			} else 
			{
				_verticalScrollBar.visible = false;
			}
			
			_verticalScrollBar.setScrollProperties(availableHeight, 0, contentHeight - availableHeight, verticalPageScrollSize);
			setVerticalScrollPosition(_verticalScrollBar.scrollPosition, false);

			if (hScrollBar) 
			{
				_horizontalScrollBar.visible = true;
				_horizontalScrollBar.x = contentPadding;
				_horizontalScrollBar.y = height - ScrollBar.WIDTH - contentPadding;
				_horizontalScrollBar.width = availableWidth;
			} else 
			{
				_horizontalScrollBar.visible = false;
			}
			
			_horizontalScrollBar.setScrollProperties(availableWidth, 0, (useFixedHorizontalScrolling) ? _maxHorizontalScrollPosition : contentWidth - availableWidth, horizontalPageScrollSize);
			setHorizontalScrollPosition(_horizontalScrollBar.scrollPosition, false);
			
			drawDisabledOverlay();
		}
		
		/**
         * @private (protected)
		 */
		protected function drawDisabledOverlay():void 
		{
			if (enabled) 
			{
				if (contains(disabledOverlay)) { removeChild(disabledOverlay); }
			} else
			{
				disabledOverlay.x = disabledOverlay.y = contentPadding;
				disabledOverlay.width = availableWidth;
				disabledOverlay.height = availableHeight;
				disabledOverlay.alpha = getStyleValue("disabledAlpha") as Number;
				addChild(disabledOverlay);
			}
		}

        /**
		 * 计算显示大小
         */
		protected function calculateAvailableSize():void
		{
			var scrollBarWidth:Number = ScrollBar.WIDTH;
			var padding:Number = contentPadding = Number(getStyleValue("contentPadding"));
			
			// figure out which scrollbars we need
			var availHeight:Number = height-2*padding - vOffset;
			vScrollBar = (_verticalScrollPolicy == ScrollPolicy.ON) || (_verticalScrollPolicy == ScrollPolicy.AUTO && contentHeight > availHeight);
			var availWidth:Number = width - (vScrollBar ? scrollBarWidth : 0) - 2 * padding;
			var maxHScroll:Number = (useFixedHorizontalScrolling) ? _maxHorizontalScrollPosition : contentWidth - availWidth;
			hScrollBar = (_horizontalScrollPolicy == ScrollPolicy.ON) || (_horizontalScrollPolicy == ScrollPolicy.AUTO && maxHScroll > 0);
			if (hScrollBar) { availHeight -= scrollBarWidth; }
			// catch the edge case of the horizontal scroll bar necessitating a vertical one:
			if (hScrollBar 
				&& !vScrollBar 
				&& _verticalScrollPolicy == ScrollPolicy.AUTO 
				&& contentHeight > availHeight)
			{
				vScrollBar = true;
				availWidth -= scrollBarWidth;
			}
			availableHeight = availHeight + vOffset;
			availableWidth = availWidth;
		}
		
		/**
         * @private (protected)
		 */
		protected function calculateContentWidth():void 
		{
			// Meant to be overriden by subclasses
		}
		
        /**
		 * 更新滚动条
         * @private (protected)
		 */
		protected function updateChildren():void 
		{
			_verticalScrollBar.enabled = _horizontalScrollBar.enabled = enabled;
			_verticalScrollBar.drawNow();
			_horizontalScrollBar.drawNow();
		}
	}
}